package com.chara.websocketdemo.handler;

import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Classname MyTextWebSocketHandler
 * @Description 自定义Websocket处理器
 * @Date 2025/8/20 15:54
 * @Author Chara
 */
@Component
public class MyTextWebSocketHandler extends TextWebSocketHandler {

    // 存储所有活跃的WebSocket线程
    private final static CopyOnWriteArrayList<WebSocketSession> sessions = new CopyOnWriteArrayList<>();

    /**
     * 连接建立成功时触发此方法
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        sessions.add(session);
        String msg = "[" + LocalDateTime.now() + "]新用户创建连接" + session.getId();
        System.out.println(msg);
        // 发送欢迎消息
        session.sendMessage(new TextMessage("欢迎光临"));
        // 广播通知其他用户
        broadCast("用户：" + session.getId().substring(0,6) + "已加入群聊,当前在线人数：" + sessions.size());
        super.afterConnectionEstablished(session);
    }

    /**
     * 接收到消息时触发此方法
     * @param session
     * @param message
     */
    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
        String payload = message.getPayload();
        System.out.println("收到来自" + session.getId() + "的消息：" + payload);

        // 回显消息给发送者
        session.sendMessage(new TextMessage("收到你说：" +  payload));

        // 广播通知其他用户
        String msg = "[" + LocalDateTime.now() + "]用户：" + session.getId().substring(0,6) + "说：" + payload;
        broadCastExceptSelf(msg, session);
    }

    /**
     * 连接关闭时触发此方法
     * @param session
     * @param status
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        sessions.remove(session);
        String msg =  "[" + LocalDateTime.now() + "]用户：" + session.getId().substring(0,6) + "已退出群聊,当前在线人数：" + sessions.size();
        System.out.println(msg);

        // 广播下辖通知
        broadCast(msg);
    }

    /**
     * 连接出错时触发此方法
     * @param session
     * @param exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("连接出错：" + session.getId() + "->" + exception.getMessage());
    }

    /*-------------------------------------工具------------------------------------------*/

    /**
     * 广播消息给除指定会话外的所有人
     * @param msg
     * @param session
     */
    private void broadCastExceptSelf(String msg, WebSocketSession session) {
        sessions.removeIf(s -> !s.isOpen());

        TextMessage textMessage = new TextMessage(msg);
        sessions.stream().filter(s -> !s.equals(session)).forEach(item ->{
            if (item.isOpen()){
                try {
                    item.sendMessage(textMessage);
                } catch (IOException e) {
                    System.err.println("广播通知失败:" + item.getId() + "->" + e.getMessage());
                    throw new RuntimeException(e);
                }
            }
        });
    }

    /**
     * 广播通知
     * @param msg
     */
    private void broadCast(String msg) {
        // 清理已关闭的连接
        sessions.removeIf(s -> !s.isOpen());

        TextMessage message = new TextMessage(msg);
        sessions.stream().forEach(item -> {
            try {
                if (item.isOpen()){
                    item.sendMessage(message);
                }
            } catch (IOException e) {
                System.err.println("广播通知失败:" + item.getId() + "->" + e.getMessage());
                throw new RuntimeException(e);
            }
        });
    }
}
